package com.jxtc.enterprise.tenant.controller;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jxtc.enterprise.admin.dto.TenantRelatedStoreDetailDTO;
import com.jxtc.enterprise.common.aspectj.TokenRequired;
import com.jxtc.enterprise.common.config.AppAuthConfig;
import com.jxtc.enterprise.common.constants.BusinessStatusConstants;
import com.jxtc.enterprise.common.constants.PrinterTypeEnum;
import com.jxtc.enterprise.common.entity.Store;
import com.jxtc.enterprise.common.entity.Tenant;
import com.jxtc.enterprise.common.exception.HttpClientException;
import com.jxtc.enterprise.common.mapper.StoreMapper;
import com.jxtc.enterprise.common.mapper.TenantMapper;
import com.jxtc.enterprise.common.utils.*;
import com.jxtc.enterprise.tenant.dto.TenantStoreRepositoryDTO;
import com.jxtc.enterprise.tenant.service.TenantStoreManageService;
import com.jxtc.enterprise.tenant.vo.req.MerchantVerifyRespVo;
import com.jxtc.enterprise.tenant.vo.req.StoreCreateReqVo;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 租户管理平台，店铺管理，新增，编辑，删除，查找店铺
 */
@RestController
@RequestMapping("/jxtc/enterprise/tenant/storeManage")
@Slf4j
@TokenRequired(role = TokenRequired.ROLE_TENANT)
@RequiredArgsConstructor
public class TenantStoreManageController {

    private final StoreMapper storeMapper;
    private final TenantMapper tenantMapper;
    private final TenantStoreManageService tenantStoreManageService;

    private final AppAuthConfig appAuthConfig;
    private final HttpClientUtil httpClientUtil;

    /**
     * 新增店铺
     *
     * @param dto
     * @return
     */
    @Operation(summary = "2.4.1 租户新增店铺接口", tags = {"2.4 租户店铺管理"}, operationId = "2.4.1")
    @PostMapping("/addNewStore")
    public Result<?> addNewStore(@RequestBody @Validated TenantStoreRepositoryDTO dto, HttpServletRequest request) {
        String requestId = UUID.randomUUID().toString();
        String tenantId = (String) request.getAttribute("userId");
        log.info("requestId {}, tenant view, /addNewStore, request body: {}, tenantId: {}", requestId, dto, tenantId);

        String host = appAuthConfig.getUrl();
        String url = String.format("%s/jxtc/customer/auth/merchantManage/verifyMerchantByPhone?phone=%s", host, dto.getMerchantPhone());
        try {
            // 调用认证服务接口判断前端传递过来的手机号是否在系统中存在
            Result<MerchantVerifyRespVo> verifyRespVoResult = httpClientUtil.get(url, new ParameterizedTypeReference<Result<MerchantVerifyRespVo>>() {
            });
            MerchantVerifyRespVo verifyRespVo = verifyRespVoResult.getData();

            if (verifyRespVo.getVerifyFlag().equals(1)) {
                // 如果调用认证服务验证前端传递的手机号已经存在，则表明该手机号在 "公司"/"个人" 任一模式中已存在
                // 直接向前端返回错误提示信息即可
                String supplyMode = "个人";
                // SELECT COUNT(*) FROM store WHERE merchant_phone = ? AND del_flag = 0
                LambdaQueryWrapper<Store> queryWrapper = new LambdaQueryWrapper<Store>()
                        .eq(Store::getMerchantPhone, dto.getMerchantPhone())
                        .eq(Store::getDelFlag, false);
                if (storeMapper.exists(queryWrapper)) {
                    // 如果该手机号所对应的店铺在 "个人订单" 系统中存在，则向前端返回的供餐模式名称为：个人
                    supplyMode = "公司";
                }

                // 拼接错误提示信息，并返回错误提示信息
                String errorMessage = String.format("手机号为 %s 的店铺已存在于【%s】系统中，请通过【同步】按钮同步信息", dto.getMerchantPhone(), supplyMode);
                throw new IllegalArgumentException(errorMessage);
            }

            // 如果调用认证服务验证前端传递的手机号不存在，则需要验证前端传递的 "店铺名称" 在系统中是否已经存在
            LambdaQueryWrapper<Store> queryWrapper = new LambdaQueryWrapper<Store>()
                    .eq(Store::getDelFlag, false)
                    .eq(Store::getName, dto.getStoreName())
                    .select(Store::getTenantId);
            List<Long> tenantIdList = storeMapper.selectObjs(queryWrapper);
            if (!tenantIdList.isEmpty()) {
                // 如果该店铺名称在 "个人订单" 系统中存在，则向前端返回错误提示信息
                LambdaQueryWrapper<Tenant> tenantQueryWrapper = new LambdaQueryWrapper<Tenant>()
                        .in(Tenant::getId, tenantIdList)
                        .select(Tenant::getNickname);
                List<String> tenantNameList = tenantMapper.selectObjs(tenantQueryWrapper);
                String tenantNames = String.join(",", tenantNameList);
                String errorMessage = String.format("已存在同名的店铺：%s，租户：%s，模式：公司。为避免同名导致的误操作，请更换名称，可在店铺名后添加地址或类别信息进行区分，比如：美味小炒-福田店，美味小炒-王师傅店", dto.getStoreName(), tenantNames);
                throw new IllegalArgumentException(errorMessage);
            }

            // 如果调用认证服务验证前端传递的手机号不存在，并且前端传递的 "店铺名称" 在个人订单系统中也不存在，则直接走正常的新增店铺流程即可
            Store store = buildStoreRepositoryInfo(tenantId, dto);
            String storeId = tenantStoreManageService.addNewStore(store, tenantId, 2);
            JSONObject resultData = new JSONObject();
            resultData.put("storeId", storeId);
            log.info("requestId {}, tenant view, /addNewStore, response successfully, {}", requestId, resultData);
            return ResultGenerator.genSuccessResult(resultData);
        } catch (HttpClientException e) {
            log.error("/addStore, 新增店铺信息时验证店主信息失败, phone: {}, e: {}", dto.getMerchantPhone(), e.getMessage());
            throw new IllegalArgumentException("新增店铺信息失败，请稍后重试");
        }
    }


    /**
     * 更新店铺信息
     *
     * @param dto
     * @return
     */
    @Operation(summary = "2.4.2 租户编辑店铺接口", tags = {"2.4 租户店铺管理"}, operationId = "2.4.2")
    @PostMapping("/editStore")
    public Result<?> editStore(
            @RequestBody() @Validated TenantStoreRepositoryDTO dto, HttpServletRequest request) {

        String requestId = UUID.randomUUID().toString();
        String tenantId = (String) request.getAttribute("userId");
        log.info("requestId {}, tenant view, /editStore, request body: {}, tenantId :{}", requestId, dto, tenantId);

        Store store = buildStoreRepositoryInfo(tenantId, dto);
        store.setId(dto.getId());
        int updateCount = storeMapper.updateById(store);
        log.info("update操作，实际影响的行数: {}", updateCount);

        return ResultGenerator.genSuccessResult("success");
    }


    /**
     * 根据店铺名称，模糊查询店铺，查询某个租户 挖掘合作的店铺列表
     *
     * @param keyword
     * @return
     */
    @Operation(summary = "2.4.3 租户查询已合作的店铺列表", tags = {"2.4 租户店铺管理"}, operationId = "2.4.3")
    @GetMapping("/queryStoreByKeyword")
    public Result<?> queryStoreByKeyword(@RequestParam(value = "keyword", required = false) String keyword,
                                         @RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
                                         @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize, HttpServletRequest request) {

        String requestId = UUID.randomUUID().toString();
        log.info("requestId {}, tenant view, /queryStoreByKeyword, keyword: {}", requestId, keyword);
        String tenantId = (String) request.getAttribute("userId");
        Page<TenantRelatedStoreDetailDTO> page = new Page<>(pageNo, pageSize);
        Page<TenantRelatedStoreDetailDTO> relatedStoreDetails = storeMapper.queryTenantRelatedStoreDetails(page, tenantId);
        List<JSONObject> formatedList = new ArrayList<>();
        for (int k = 0; k < relatedStoreDetails.getRecords().size(); k++) {
            TenantRelatedStoreDetailDTO storeDetail = relatedStoreDetails.getRecords().get(k);
            if (StringUtils.isNotEmpty(keyword) && !storeDetail.getName().contains(keyword)) {
                continue;
            }
            // 主要是为了 返回转换成小数的店铺合作价格，同时不返回 del_flag, create_time, last_update_time，才进行如下操作
            Float storePriceInYuan = 1.0F * storeDetail.getStorePrice() / 100;
            JSONObject formattedStoreInfo = new JSONObject();
            formattedStoreInfo.put("id", storeDetail.getId());
            formattedStoreInfo.put("name", storeDetail.getName());
            formattedStoreInfo.put("logo", storeDetail.getLogo());
            formattedStoreInfo.put("address", storeDetail.getAddress());
            formattedStoreInfo.put("longitude", storeDetail.getLongitude());
            formattedStoreInfo.put("latitude", storeDetail.getLatitude());
            formattedStoreInfo.put("description", storeDetail.getDescription());
            formattedStoreInfo.put("foodTypes", storeDetail.getFoodTypes());
            formattedStoreInfo.put("merchantIdNum", storeDetail.getMerchantIdNum());
            formattedStoreInfo.put("merchantPhone", storeDetail.getMerchantPhone());
            formattedStoreInfo.put("merchantWechatNum", storeDetail.getMerchantWechatNum());
            formattedStoreInfo.put("merchantName", storeDetail.getMerchantName());
            formattedStoreInfo.put("businessStart", storeDetail.getBusinessStart());
            formattedStoreInfo.put("businessEnd", storeDetail.getBusinessEnd());
            formattedStoreInfo.put("qualification", storeDetail.getQualifications());
            formattedStoreInfo.put("storePrice", storePriceInYuan);
            formattedStoreInfo.put("merchantLoginPasswd", storeDetail.getMerchantLoginPasswd());
            formattedStoreInfo.put("limitCount", storeDetail.getLimitCount());
            formattedStoreInfo.put("printerSn", storeDetail.getPrinterSn());
            formattedStoreInfo.put("mergeFoodItems", storeDetail.getMergeFoodItems());
            formattedStoreInfo.put("tenantId", storeDetail.getTenantId());
            formattedStoreInfo.put("tenantName", storeDetail.getTenantName());

            if (storeDetail.getPrintLabelType() == 1) {
                // 数据库中 print_label_type 列的值 1：贴纸
                formattedStoreInfo.put("printerType", PrinterTypeEnum.TIE_ZHI_PRINTER.getPrinterTypeName());
            } else if (storeDetail.getPrintLabelType() == 2) {
                // 数据库中 print_label_type 列的值 2：外卖小票
                formattedStoreInfo.put("printerType", PrinterTypeEnum.XIAO_PIAO_PRINTER.getPrinterTypeName());
            } else {
                log.error("requestId: {}, tenant view, /queryStoreByKeyword, 管理平台，根据关键字，查询店铺列表接口，获取打印机类型异常，店铺详情：{}", requestId, storeDetail);
            }

            formatedList.add(formattedStoreInfo);
        }

        Result<JSONObject> result = new Result<>();
        result.setCode(ResultCode.SUCCESS);
        JSONObject resultData = new JSONObject();
        resultData.put("currentPage", pageNo);
        resultData.put("totalPages", relatedStoreDetails.getPages());
        resultData.put("totalRows", relatedStoreDetails.getTotal());
        resultData.put("stores", formatedList);
        result.setData(resultData);
        log.info("requestId {}, tenant view, /queryStoreByKeyword, response successfully", requestId);
        return result;
    }


    /**
     * 根据店铺id，删除店铺
     *
     * @param storeId
     * @return
     */
    @Operation(summary = "2.4.4 租户删除店铺", tags = {"2.4 租户店铺管理"}, operationId = "2.4.4")
    @DeleteMapping("/deleteStore")
    public Result<?> deleteStore(@RequestParam(value = "storeId") String storeId) {
        String requestId = UUID.randomUUID().toString();
        log.info("requestId {}, tenant view, /deleteStore, storeId: {}", requestId, storeId);

        Store store = new Store();
        store.setId(storeId);
        store.setDelFlag(true);
        int count = storeMapper.updateById(store);
        log.info("requestId {}, tenant view, /deleteStore, response successfully 软删除记录，实际影响行数: {}", requestId, count);

        return ResultGenerator.genSuccessResult("success");
    }


    /**
     * 创建 JxStoreRepositoryDo 对象，并填充各个字段的值
     * 使用场景
     * 1. 新增或更新店铺信息时，前端调用接口时，会传递店铺信息，包括需要修改的和没有修改的，为了简化接口传参定义，更新时，属性值无论是否有更新，都一起传递给后端，后端直接更新整条记录，不用再去区分更新那些字段，不更新那些字段
     *
     * @param storeRepositoryVo
     * @return
     */
    private Store buildStoreRepositoryInfo(String tenantId, TenantStoreRepositoryDTO storeRepositoryVo) {
        Store storeRepositoryDo = new Store();
        storeRepositoryDo.setTenantId(tenantId);
        storeRepositoryDo.setName(storeRepositoryVo.getStoreName());
        storeRepositoryDo.setDescription(storeRepositoryVo.getStoreDescription());
        storeRepositoryDo.setLogo(storeRepositoryVo.getLogo());
        storeRepositoryDo.setStorePrice(storeRepositoryVo.getStorePriceInFen());
        storeRepositoryDo.setMerchantName(storeRepositoryVo.getMerchantName());
        String formatedIdNum = storeRepositoryVo.getMerchantIdNum().length() > 18 ? storeRepositoryVo.getMerchantIdNum().substring(0, 18) : storeRepositoryVo.getMerchantIdNum();
        storeRepositoryDo.setMerchantIdNum(formatedIdNum);
        String formatedPhoneNum = storeRepositoryVo.getMerchantPhone().length() > 11 ? storeRepositoryVo.getMerchantPhone().substring(0, 11) : storeRepositoryVo.getMerchantPhone();
        storeRepositoryDo.setMerchantPhone(formatedPhoneNum);

        if (storeRepositoryVo.getMerchantLoginPasswd() != null && !storeRepositoryVo.getMerchantLoginPasswd().isEmpty()) {
            storeRepositoryDo.setMerchantLoginPasswd(storeRepositoryVo.getMerchantLoginPasswd());
        }

        storeRepositoryDo.setMerchantWechatNum(storeRepositoryVo.getMerchantWechatNum());
        storeRepositoryDo.setAddress(storeRepositoryVo.getStoreAddress());
        storeRepositoryDo.setLongitude(storeRepositoryVo.getLongitude());
        storeRepositoryDo.setLatitude(storeRepositoryVo.getLatitude());
        storeRepositoryDo.setCategoryId(storeRepositoryVo.getCategoryId());
        storeRepositoryDo.setCategoryName(storeRepositoryVo.getCategoryName());
        if (storeRepositoryVo.getFoodType() != null) {
            storeRepositoryDo.setFoodTypes(storeRepositoryVo.getFoodType().toJSONString());
        }
        storeRepositoryDo.setBusinessStart(storeRepositoryVo.getBusinessStart());
        storeRepositoryDo.setBusinessEnd(storeRepositoryVo.getBusinessEnd());
        // storeRepositoryDo.setCreateTime(LocalDateTime.now());
        if (storeRepositoryVo.getLimitCount() == null) {
            storeRepositoryDo.setLimitCount(999);// 使用默认值, todo 做成全局配置项
        } else if (storeRepositoryVo.getLimitCount() == 0) {
            storeRepositoryDo.setLimitCount(Integer.MAX_VALUE);// 0 表示不限购
        } else {
            storeRepositoryDo.setLimitCount(storeRepositoryVo.getLimitCount());
        }
        if (StringUtils.isBlank(storeRepositoryVo.getPrinterSn())) {
            log.warn("店铺使用的飞鹅打印机序列号为空，可能使用的是 其他打印机");
            storeRepositoryDo.setPrinterSn("empty sn");
        } else {
            storeRepositoryDo.setPrinterSn(storeRepositoryVo.getPrinterSn());
        }

        if (!StringUtils.isBlank(storeRepositoryVo.getQualification())) {
            // TODO: 当前前端传递过来的是单个图片链接，后续如果修改成 List<String> 后，该字段应使用 JSON Array 进行存储
            storeRepositoryDo.setQualifications(storeRepositoryVo.getQualification());
        }

        if (PrinterTypeEnum.TIE_ZHI_PRINTER.getPrinterTypeName().equals(storeRepositoryVo.getPrinterType())) {
            // 1 贴纸打印机
            storeRepositoryDo.setPrintLabelType(PrinterTypeEnum.TIE_ZHI_PRINTER.getTypeCode());
        } else if (PrinterTypeEnum.XIAO_PIAO_PRINTER.getPrinterTypeName().equals(storeRepositoryVo.getPrinterType())) {
            // 2 小票打印机
            storeRepositoryDo.setPrintLabelType(PrinterTypeEnum.XIAO_PIAO_PRINTER.getTypeCode());
        } else {
            log.error("编辑店铺信息，传递的打印机类型为：{} ，传参无法识别", storeRepositoryVo.getPrinterType());
        }

        storeRepositoryDo.setMergeFoodItems(storeRepositoryVo.getMergeFoodItems());
        return storeRepositoryDo;
    }


    /**
     * 同步店铺信息
     *
     * @return 同步成功时，返回 code 为 200，data 为空；同步失败时，返回 code 为 400，message 给出错误提示信息
     */
    @PostMapping("/syncStoreInfo")
    public Result<Void> syncStoreInfo(@Valid @RequestBody StoreCreateReqVo reqVo, HttpServletRequest request) {
        String requestId = UUID.randomUUID().toString();
        String tenantId = (String) request.getAttribute("userId");
        log.info("requestId {}, tenant view, /syncStoreInfo, request body: {}, tenantId: {}", requestId, reqVo, tenantId);

        // 判断输入的手机号，在该租户，当前模式，是否已经存在
        LambdaQueryWrapper<Store> queryWrapper = new LambdaQueryWrapper<Store>()
                .eq(Store::getTenantId, tenantId)
                .eq(Store::getMerchantPhone, reqVo.getMerchantPhone())
                .eq(Store::getDelFlag, false);
        if (storeMapper.exists(queryWrapper)) {
            // 如果该店主手机号在当前模式下的，该租户已经录入过，则向前端返回错误提示信息
            String errorMessage = "要同步的手机号所关联店铺在当前模式已存在，不能同步已存在的店铺";
            throw new IllegalArgumentException(errorMessage);
        }

        // 如果该手机号尚未被该租户录入，则走正常的新增店铺操作即可
        Store store = buildStoreRepositoryInfo(tenantId, reqVo);
        tenantStoreManageService.addNewStore(store, tenantId, 1);

        return ResultGenerator.genSuccessResult();
    }

    private Store buildStoreRepositoryInfo(String tenantId, StoreCreateReqVo reqVo) {
        Store store = new Store();
        store.setTenantId(tenantId);
        store.setName(reqVo.getStoreName());
        store.setDescription(reqVo.getStoreDescription());
        store.setLogo(reqVo.getStoreImage());
        store.setStorePrice(CurrencyUtil.yuanToFen(new BigDecimal(reqVo.getStorePrice())));
        store.setMerchantName(reqVo.getMerchantName());
        String formatedIdNum = reqVo.getMerchantIdNum().length() > 18 ? reqVo.getMerchantIdNum().substring(0, 18) : reqVo.getMerchantIdNum();
        store.setMerchantIdNum(formatedIdNum);
        String formatedPhoneNum = reqVo.getMerchantPhone().length() > 11 ? reqVo.getMerchantPhone().substring(0, 11) : reqVo.getMerchantPhone();
        store.setMerchantPhone(formatedPhoneNum);

        if (reqVo.getMerchantLoginPassword() != null && !reqVo.getMerchantLoginPassword().isEmpty()) {
            store.setMerchantLoginPasswd(reqVo.getMerchantLoginPassword());
        }

        store.setMerchantWechatNum(reqVo.getMerchantWechatNum());
        store.setAddress(reqVo.getStoreAddress());
        store.setLongitude(Double.valueOf(reqVo.getStoreLongitude()));
        store.setLatitude(Double.valueOf(reqVo.getStoreLatitude()));
        store.setCategoryId(reqVo.getCategoryId());
        store.setCategoryName(reqVo.getCategoryName());
        if (reqVo.getFoodTypes() != null) {
            store.setFoodTypes(JSONObject.toJSONString(reqVo.getFoodTypes()));
        }
        store.setBusinessStart(reqVo.getBusinessStart());
        store.setBusinessEnd(reqVo.getBusinessEnd());
        if (reqVo.getLimitCount() == null) {
            // 使用默认值, todo 做成全局配置项
            store.setLimitCount(999);
        } else if (reqVo.getLimitCount() == 0) {
            // 0 表示不限购
            store.setLimitCount(Integer.MAX_VALUE);
        } else {
            store.setLimitCount(reqVo.getLimitCount());
        }
        if (StringUtils.isBlank(reqVo.getPrinterSn())) {
            log.warn("店铺使用的飞鹅打印机序列号为空，可能使用的是 其他打印机");
            store.setPrinterSn("empty sn");
        } else {
            store.setPrinterSn(reqVo.getPrinterSn());
        }

        if (!StringUtils.isBlank(reqVo.getStoreQualification())) {
            // TODO: 当前前端传递过来的是单个图片链接，后续如果修改成 List<String> 后，该字段应使用 JSON Array 进行存储
            store.setQualifications(reqVo.getStoreQualification());
        }

        if (PrinterTypeEnum.TIE_ZHI_PRINTER.getTypeCode().equals(reqVo.getPrinterType())) {
            // 1 贴纸打印机
            store.setPrintLabelType(PrinterTypeEnum.TIE_ZHI_PRINTER.getTypeCode());
        } else if (PrinterTypeEnum.XIAO_PIAO_PRINTER.getTypeCode().equals(reqVo.getPrinterType())) {
            // 2 小票打印机
            store.setPrintLabelType(PrinterTypeEnum.XIAO_PIAO_PRINTER.getTypeCode());
        } else {
            log.error("编辑店铺信息，传递的打印机类型为：{} ，传参无法识别", reqVo.getPrinterType());
        }

        store.setMergeFoodItems(reqVo.getMergeFoodItem());
        return store;
    }
}
